﻿//======================================================================
//
//	Cross-Platform XNA Menu System
//  http://cpxms.codeplex.com/
//
//  All code and content licensed under Microsoft Public License (Ms-PL)	
//
//======================================================================
//
//	File:		Checkbox.cs
//
//	Author:		MJP
//
//	Date:		05/15/09
//
//======================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using System.Drawing.Design;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace CPXMenu
{
	/// <summary>
	/// An item that has a checked and unchecked state.
	/// </summary>
	[Description("An item that has a checked and unchecked state.")]
	[CanHaveChildren(false)]
	[IconKey("Checkbox")]
	[Selectable(true)]
	[Movable(true)]
	[Sizeable(true)]
	[CanCopyPaste(true)]
	[CanHaveFocus(true)]
	public class Checkbox : MenuItem
	{
		private ImageState uncheckedImageState = new ImageState();
		private ImageState uncheckedFocusedImageState = new ImageState();
		private ImageState checkedImageState = new ImageState();
		private ImageState checkedFocusedImageState = new ImageState();
        private ImageState textAreaImageState = new ImageState();
		private TextState textState = new TextState();
		private CheckboxDesignState designState = CheckboxDesignState.Unchecked;
		private bool isChecked = false;

		public const string DefaultUncheckedImage = "CPXMenu Content\\Textures\\CheckboxUnchecked";
		public const string DefaultUncheckedFocusedImage = "CPXMenu Content\\Textures\\CheckboxUncheckedFocused";
		public const string DefaultCheckedImage = "CPXMenu Content\\Textures\\CheckboxChecked";
		public const string DefaultCheckedFocusedImage = "CPXMenu Content\\Textures\\CheckboxCheckedFocused";
		public const string DefaultFont = "CPXMenu Content\\Fonts\\ArialS";

		/// <summary>
		/// Gets or sets the ImageState representing the Checkbox's appearance when unchecked
		/// </summary>
		[Browsable(true)]
		[Category("Appearance")]
		[Description("The appearance of the Checkbox when it's unchecked")]
		public ImageState UncheckedImageState
		{
			get { return uncheckedImageState; }
			set
			{
				uncheckedImageState = value;
				SetImageStates();
			}
		}

		/// <summary>
		/// Gets or sets the ImageState representing the Checkbox's appearance when unchecked and focused
		/// </summary>
		[Browsable(true)]
		[Category("Appearance")]
		[Description("The appearance of the Checkbox when it's unchecked and in the focused state")]
		public ImageState UncheckedFocusedImageState
		{
			get { return uncheckedFocusedImageState; }
			set
			{
				uncheckedFocusedImageState = value;
				SetImageStates();
			}
		}

		/// <summary>
		/// Gets or sets the ImageState representing the Checkbox's appearance when checked
		/// </summary>
		[Browsable(true)]
		[Category("Appearance")]
		[Description("The appearance of the Checkbox when checked")]
		public ImageState CheckedImageState
		{
			get { return checkedImageState; }
			set
			{
				checkedImageState = value;
				SetImageStates();
			}
		}
		
		/// <summary>
		/// Gets or sets the ImageState representing the Checkbox's appearance when checked and focused
		/// </summary>
		[Browsable(true)]
		[Category("Appearance")]
		[Description("The appearance of the Checkbox when checked and focused")]
		public ImageState CheckedFocusedImageState
		{
			get { return checkedFocusedImageState; }
			set
			{
				checkedFocusedImageState = value;
				SetImageStates();
			}
		}

        /// <summary>
        /// Gets or sets the ImageState drawn in the text area of the Checkbox
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("The ImageState drawn in the text area of the Checkbox")]
        public ImageState TextAreaImageState
        {
            get { return textAreaImageState; }
            set
            {
                textAreaImageState = value;
                SetImageStates();
            }
        }

		/// <summary>
		/// Gets or sets the TextState representing the Checkbox's appearance when idle
		/// </summary>
		[Browsable(true)]
		[Category("Text")]
		[Description("The text drawn on the checkbox")]
		public TextState TextState
		{
			get { return textState; }
			set
			{
				textState = value;
				SetTextStates();
			}
		}		

		/// <summary>
		/// Gets or sets a value indicating which state should be drawn when in design mode
		/// </summary>
		[Browsable(true)]
		[Category("Design")]
		[Description("The state of the Checkbox in design mode")]
		[XmlIgnore]
		public CheckboxDesignState DesignState
		{
			get { return designState; }
			set { designState = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether 
		/// </summary>
		[Browsable(false)]
		[XmlIgnore]
		public bool IsChecked
		{
			get { return isChecked; }
			set 
			{
				if (isChecked != value)
				{
					isChecked = value;
					if (value)
						OnChecked();
					else
						OnUnchecked();
				}
			}
		}

		/// <summary>
		/// Creates a Checkbox instance
		/// </summary>
		public Checkbox()
			: base()
		{
			Dimensions = new Point(300, 100);

			uncheckedImageState.TextureName = DefaultUncheckedImage;
			uncheckedImageState.TransitionTime = 0.5f;
			uncheckedFocusedImageState.TextureName = DefaultUncheckedFocusedImage;
			uncheckedFocusedImageState.TransitionTime = 0.5f;
			checkedImageState.TextureName = DefaultCheckedImage;
			checkedImageState.TransitionTime = 0.5f;
			checkedFocusedImageState.TextureName = DefaultCheckedFocusedImage;
			checkedFocusedImageState.TransitionTime = 0.5f;

			textState.FontName = DefaultFont;
			textState.HorizontalJustification = TextHorizontalJustification.Left;
			textState.VerticalJustification = TextVerticalJustification.Center;

			SetImageStates();
			SetTextStates();
		}

		/// <summary>
		/// Initializes the item
		/// </summary>
		/// <param name="parentProject">The parent MenuProject</param>
		/// <param name="contentManager">The ContentManager from which to load content</param>
		/// <param name="graphicsDevice">The GraphicsDevice to use for rendering</param>
		internal override void Initialize(MenuProject parentProject, ContentManager contentManager, GraphicsDevice graphicsDevice)
		{
			base.Initialize(parentProject, contentManager, graphicsDevice);


		}


		/// <summary>
		/// Renders the Checkbox
		/// </summary>
		/// <param name="dt">Time delta</param>
		/// <param name="spriteBatch">The shared SpriteBatch</param>
		/// <param name="lineManager">The shared LineManager</param>
		/// <param name="selected">true if currently selected</param>
		/// <param name="highlighted">true if currently highlighted</param>
		internal override void RenderThis(float dt, SpriteBatch spriteBatch, RoundLineManager lineManager, bool selected, bool highlighted)
		{
			if (DesignMode)
				ImageStateIndex = (int)DesignState;
			else
			{
				if (IsChecked)
					if (Focused)
						ImageStateIndex = (int)CheckboxDesignState.CheckedFocused;
					else
						ImageStateIndex = (int)CheckboxDesignState.Checked;
				else
					if (Focused)
						ImageStateIndex = (int)CheckboxDesignState.UncheckedFocused;
					else
						ImageStateIndex = (int)CheckboxDesignState.Unchecked;
			}

			TextStateIndex = 0;

            if (textAreaImageState != null)
            {
                Rectangle drawRect = DetermineTextDrawRect();
                drawRect.Y += (int)(drawRect.Height * 0.2f);
                drawRect.Height -= (int)(drawRect.Height * 0.4f);
                textAreaImageState.Render(dt, spriteBatch, drawRect, 1.0f);
            }

			base.RenderThis(dt, spriteBatch, lineManager, selected, highlighted);
		}

		/// <summary>
		/// Determines the rectangle to which the current ImageState should be fit to
		/// </summary>
		/// <returns>the rectangle to which the current ImageState should be fit to</returns>
		protected override Rectangle DetermineImageDrawRect()
		{			
			ImageState currentImageState = CurrentImageState;
			if (currentImageState != null)
			{
				Rectangle drawRect = BoundingRect;
				float scale = drawRect.Height / (float)currentImageState.ImageTexture.Height;
				drawRect.Width = (int)(currentImageState.ImageTexture.Width * scale);
				return drawRect;
			}
			else
				return new Rectangle();
		}

		/// <summary>
		/// Determines the rectangle to which the current TextState should be fit to
		/// </summary>
		/// <returns>the rectangle to which the current TextState should be fit to</returns>
		protected override Rectangle DetermineTextDrawRect()
		{
			TextState currentTextState = CurrentTextState;
			if (currentTextState != null)
			{
				Rectangle imageRect = DetermineImageDrawRect();
				Rectangle drawRect = BoundingRect;
				drawRect.Width = drawRect.Width - imageRect.Width;
				drawRect.X += imageRect.Width;
				return drawRect;
			}
			else
				return new Rectangle();
		}

        /// <summary>
        /// Creates a clone of the item
        /// </summary>
        /// <returns>A clone of the item</returns>
        public override MenuItem Clone()
        {
            Checkbox clone = (Checkbox)base.Clone();

            clone.uncheckedImageState = this.uncheckedImageState.Clone();
            clone.uncheckedFocusedImageState = this.uncheckedFocusedImageState.Clone();
            clone.checkedImageState = this.checkedImageState.Clone();
            clone.checkedFocusedImageState = this.checkedFocusedImageState.Clone();
			clone.textAreaImageState = this.textAreaImageState.Clone();
            clone.SetImageStates();

            clone.textState = this.textState.Clone();
            clone.SetTextStates();

            return clone;
        }

		/// <summary>
		/// Called when the Checkbox is clicked (pressed and depressed while maintaining focus)
		/// </summary>
		protected override void OnClicked()
		{
			base.OnClicked();

			IsChecked = !IsChecked;
		}

		/// <summary>
		/// Called when the user checks this Checkbox
		/// </summary>
		protected virtual void OnChecked()
		{
			if (Checked != null)
				Checked(this);
		}

		/// <summary>
		/// Called when the user unchecks this Checkbox
		/// </summary>
		protected virtual void OnUnchecked()
		{
			if (Unchecked != null)
				Unchecked(this);
		}

		/// <summary>
		/// Puts all ImageStates in the ImageStates collection
		/// </summary>
		private void SetImageStates()
		{
			ImageStates.Clear();
			ImageStates.Add(uncheckedImageState);
			ImageStates.Add(uncheckedFocusedImageState);
			ImageStates.Add(checkedImageState);
			ImageStates.Add(checkedFocusedImageState);
            ImageStates.Add(textAreaImageState);
		}

		/// <summary>
		/// Puts all TextStates in the TextStates collection
		/// </summary>
		private void SetTextStates()
		{
			TextStates.Clear();
			TextStates.Add(textState);
		}

		/// <summary>
		/// Raised when the user checks the checkbox
		/// </summary>
		public event MenuItemDelegate Checked;

		/// <summary>
		/// Raised when the user unchecks the checkbox
		/// </summary>
		public event MenuItemDelegate Unchecked;

	}

	/// <summary>
	/// Used to indicate which state the Checkbox should be in
	/// when in design-mode.
	/// </summary>
	public enum CheckboxDesignState
	{
		Unchecked = 0,
		UncheckedFocused = 1,
		Checked = 2,
		CheckedFocused = 3
	}
}